import edu.umd.cs.piccolo.PCamera;
import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.util.PBounds;

public class ColorGridNode extends PNode {
	private final int DEFAULT_NUM_DAYS = 3;
	private final int DEFAULT_NUM_WEEKS = 3;
	private final int DEFAULT_ANIMATION_MILLIS = 250;
	private final float FOCUS_SIZE_PERCENT = 0.75f;

	private int numDays = DEFAULT_NUM_DAYS;
	private int numWeeks = DEFAULT_NUM_WEEKS;
	private int daysExpanded = 0;
	private int weeksExpanded = 0;
	private boolean zoomed = false;
	private double focusX = 0;
	private double focusY = 0;
	private double parentOffsetX = 0;
	private double parentOffsetY = 0;
	private float hMin;
	private float hMax;
	private float bMin;
	private float bMax;
	private int[] gFilter;

	private PCamera camera;
	private DbHandler db;
	private ColorGridNode calendarNode;
	private ColorBoxNode focusedDay = null;
	private PBounds prevCameraView;
	private PBounds nextCameraView;

	public ColorGridNode() {
		//for subclass only
	}
	
	public ColorGridNode(PCamera c, DbHandler d, ColorGridNode cgn, float hm, float hM, float bm, float bM, int[] filter) {
		camera = c;
		db = d;
		calendarNode = cgn;
		hMin = hm;
		hMax = hM;
		bMin = bm;
		bMax = bM;
		float hStep = (hMax-hMin)/numDays;
		float bStep = (bMax-bMin)/numWeeks;
		float boxH = hMin;
		float boxB = bMax;
		gFilter = filter;
		
		for (int week = 0; week < numWeeks; week++) {
			for (int day = 0; day < numDays; day++) {
				addChild(new ColorBoxNode(camera, db, week, day, boxH, boxH+hStep, boxB-bStep, boxB, gFilter));
				boxH+=hStep;
			}
			boxH=hMin;
			boxB-=bStep;
		}

		ColorGridNode.this.addInputEventListener(new PBasicInputEventHandler() {
			@Override
			public void mouseReleased(PInputEvent event) {
				if (event.isLeftMouseButton() && !event.isShiftDown()) {
					ColorBoxNode pickedDay = (ColorBoxNode) event.getPickedNode();
					if (!pickedDay.hasWidthFocus()
							|| !pickedDay.hasHeightFocus()) {
						setFocusDay(pickedDay, true);

						PBounds oldBounds = camera.getViewBounds();
						if (!zoomed) {
							nextCameraView = new PBounds(oldBounds.getX()+parentOffsetX, 
									oldBounds.getY()+parentOffsetY, 
									getWidth(),
									getHeight());
							calendarNode.setPrevCameraView(nextCameraView);
							camera.animateViewToCenterBounds(nextCameraView, true, 500);
							zoomed = true;
						}
						else
							calendarNode.setPrevCameraView(oldBounds);
					}
					else if(pickedDay.getChildrenCount()==0) {
						focusedDay.addChild(calendarNode);
					}
					focusedDay = pickedDay;
					event.setHandled(true);
				}
				else if (event.isRightMouseButton()) {
					if (focusedDay != null) {
						focusedDay = null;
						zoomed = false;
						setFocusDay(null, true);
						if(prevCameraView != null)
							camera.animateViewToCenterBounds(prevCameraView, true, 500);
						event.setHandled(true);
					}
				}
				else if (event.isMiddleMouseButton() ||
							(event.isLeftMouseButton() && event.isShiftDown())) {
					if (focusedDay != null) {
						if (focusedDay.getChildrenCount()>0) {
							focusedDay.removeAllChildren();
							focusedDay.prepareColorCount(gFilter);
						}
						else
							focusedDay.addChild(calendarNode);
						event.setHandled(true);
					}
				}
			}
		});
	}


	public ColorBoxNode getDay(int week, int day) {
		return (ColorBoxNode) getChild((week * numDays) + day);
	}
	
	public ColorGridNode getSubNode() {
		return calendarNode;
	}
	
	public void setParentOffsetX(double x) {
		parentOffsetX = x;
	}
	
	public void setParentOffsetY(double y) {
		parentOffsetY = y;
	}
	
	protected void setPrevCameraView(PBounds oldBounds) {
		prevCameraView = oldBounds;
	}
	
	public void setFilter(int[] filter){
		gFilter = filter;
		if(calendarNode != null){
			calendarNode.setFilter(filter);
		}
		if(focusedDay != null){
			focusedDay.setFilter(filter);
		}
	}
	
	public void setFocusDay(ColorBoxNode focusDay, boolean animate) {
		for (int i = 0; i < getChildrenCount(); i++) {
			ColorBoxNode each = (ColorBoxNode) getChild(i);
			each.setHasWidthFocus(false);
			each.setHasHeightFocus(false);
			each.setFilter(gFilter);
		}

		if (focusDay == null) {
			daysExpanded = 0;
			weeksExpanded = 0;
		} else {
			focusDay.setHasWidthFocus(true);
			daysExpanded = 1;
			weeksExpanded = 1;

			for (int i = 0; i < numDays; i++) {
				getDay(focusDay.getWeek(), i).setHasHeightFocus(true);
			}

			for (int i = 0; i < numWeeks; i++) {
				getDay(i, focusDay.getDay()).setHasWidthFocus(true);
			}
		}
		

		layoutChildren(focusDay, animate);
	}

	protected void layoutChildren(ColorBoxNode focusDay, boolean animate) {
		double focusWidth = 0;
		double focusHeight = 0;

		if (daysExpanded != 0 && weeksExpanded != 0) {
			focusWidth = (getWidth() * FOCUS_SIZE_PERCENT) / daysExpanded;
			focusHeight = (getHeight() * FOCUS_SIZE_PERCENT)
			/ weeksExpanded;
		}

		double collapsedWidth = (getWidth() - (focusWidth * daysExpanded))
		/ (numDays - daysExpanded);
		double collapsedHeight = (getHeight() - (focusHeight * weeksExpanded))
		/ (numWeeks - weeksExpanded);

		double xOffset = 0;
		double yOffset = 0;
		double rowHeight = 0;
		ColorBoxNode each = null;

		for (int week = 0; week < numWeeks; week++) {
			for (int day = 0; day < numDays; day++) {
				each = getDay(week, day);
				if (each == focusDay) {
					focusX = xOffset;
					focusY = yOffset;
				}
				double width = collapsedWidth;
				double height = collapsedHeight;

				if (each.hasWidthFocus())
					width = focusWidth;
				if (each.hasHeightFocus())
					height = focusHeight;

				if (animate) {
					each.animateToBounds(xOffset, yOffset, width, height,
							DEFAULT_ANIMATION_MILLIS).setStepRate(0);
				} else {
					each.setBounds(xOffset, yOffset, width, height);
				}

				xOffset += width;
				rowHeight = height;
			}
			xOffset = 0;
			yOffset += rowHeight;
		}

		
		calendarNode.removeFromParent();			

		if (focusDay != null) {
			if (calendarNode instanceof BottomColorGridNode)
				calendarNode = new BottomColorGridNode(camera, db,
														focusDay.getHMin(),
														focusDay.getHMax(),
														focusDay.getBMin(),
														focusDay.getBMax(), gFilter);
			else
				calendarNode = new ColorGridNode(camera, db, calendarNode.getSubNode(),
													focusDay.getHMin(),
													focusDay.getHMax(),
													focusDay.getBMin(),
													focusDay.getBMax(), gFilter);
			focusDay.addChild(calendarNode);
			calendarNode.setPrevCameraView(nextCameraView);
			calendarNode.setBounds(focusX, focusY, focusWidth - 1,
					focusHeight - 1);
			calendarNode.setOffset(focusX, focusY);
			calendarNode.setParentOffsetX(focusX);
			calendarNode.setParentOffsetY(focusY);
			
			calendarNode.layoutChildren(null, false);
			calendarNode.setFilter(gFilter);
		}


	}
}